From: Isaku Yamahata Date: Fri, 5 Dec 2008 06:43:08 +0000 (+0900) Subject: IA64: implement PHYSDEVOP_pirq_eoi_gmfn and related stuff. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~14038 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=29bfb6999af29d12a886ff482b363bb981d5334c;p=xen.git IA64: implement PHYSDEVOP_pirq_eoi_gmfn and related stuff. This patch is ia64 counter part of 18844:c820bf73a914. Signed-off-by: Isaku Yamahata --- diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c index 0a2b22a123..d59c1badca 100644 --- a/xen/arch/ia64/xen/domain.c +++ b/xen/arch/ia64/xen/domain.c @@ -1653,6 +1653,11 @@ int domain_relinquish_resources(struct domain *d) /*fallthrough*/ case RELRES_mm_teardown: + if (d->arch.pirq_eoi_map != NULL) { + put_page(virt_to_page(d->arch.pirq_eoi_map)); + d->arch.pirq_eoi_map = NULL; + } + /* Tear down shadow mode stuff. */ ret = mm_teardown(d); if (ret != 0) diff --git a/xen/arch/ia64/xen/hypercall.c b/xen/arch/ia64/xen/hypercall.c index e83dab6132..b2af334617 100644 --- a/xen/arch/ia64/xen/hypercall.c +++ b/xen/arch/ia64/xen/hypercall.c @@ -341,10 +341,42 @@ long do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) ret = -EFAULT; if ( copy_from_guest(&eoi, arg, 1) != 0 ) break; + ret = -EINVAL; + if ( eoi.irq < 0 || eoi.irq >= NR_IRQS ) + break; + if ( current->domain->arch.pirq_eoi_map ) + evtchn_unmask(current->domain->pirq_to_evtchn[eoi.irq]); ret = pirq_guest_eoi(current->domain, eoi.irq); break; } + case PHYSDEVOP_pirq_eoi_gmfn: { + struct physdev_pirq_eoi_gmfn info; + unsigned long mfn; + + BUILD_BUG_ON(NR_IRQS > (PAGE_SIZE * 8)); + + ret = -EFAULT; + if ( copy_from_guest(&info, arg, 1) != 0 ) + break; + + ret = -EINVAL; + mfn = gmfn_to_mfn(current->domain, info.gmfn); + if ( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), current->domain) ) + break; + + if ( cmpxchg(¤t->domain->arch.pirq_eoi_map_mfn, 0, mfn) != 0 ) + { + put_page(mfn_to_page(mfn)); + ret = -EBUSY; + break; + } + + current->domain->arch.pirq_eoi_map = mfn_to_virt(mfn); + ret = 0; + break; + } + /* Legacy since 0x00030202. */ case PHYSDEVOP_IRQ_UNMASK_NOTIFY: { ret = pirq_guest_unmask(current->domain); diff --git a/xen/arch/ia64/xen/irq.c b/xen/arch/ia64/xen/irq.c index 4345222300..86c70670ab 100644 --- a/xen/arch/ia64/xen/irq.c +++ b/xen/arch/ia64/xen/irq.c @@ -312,16 +312,41 @@ typedef struct { struct domain *guest[IRQ_MAX_GUESTS]; } irq_guest_action_t; +static inline void set_pirq_eoi(struct domain *d, unsigned int irq) +{ + if ( d->arch.pirq_eoi_map ) + set_bit(irq, d->arch.pirq_eoi_map); +} + +static inline void clear_pirq_eoi(struct domain *d, unsigned int irq) +{ + if ( d->arch.pirq_eoi_map ) + clear_bit(irq, d->arch.pirq_eoi_map); +} + +static void _irq_guest_eoi(irq_desc_t *desc) +{ + irq_guest_action_t *action = (irq_guest_action_t *)desc->action; + unsigned int i, vector = desc - irq_desc; + + if ( !(desc->status & IRQ_GUEST_EOI_PENDING) ) + return; + + for ( i = 0; i < action->nr_guests; ++i ) + clear_pirq_eoi(action->guest[i], vector); + + desc->status &= ~(IRQ_INPROGRESS|IRQ_GUEST_EOI_PENDING); + desc->handler->enable(vector); +} + static struct timer irq_guest_eoi_timer[NR_IRQS]; static void irq_guest_eoi_timer_fn(void *data) { irq_desc_t *desc = data; - unsigned vector = desc - irq_desc; unsigned long flags; spin_lock_irqsave(&desc->lock, flags); - desc->status &= ~IRQ_INPROGRESS; - desc->handler->enable(vector); + _irq_guest_eoi(desc); spin_unlock_irqrestore(&desc->lock, flags); } @@ -355,8 +380,22 @@ void __do_IRQ_guest(int irq) if ( already_pending == action->nr_guests ) { - desc->handler->disable(irq); stop_timer(&irq_guest_eoi_timer[irq]); + desc->handler->disable(irq); + desc->status |= IRQ_GUEST_EOI_PENDING; + for ( i = 0; i < already_pending; ++i ) + { + d = action->guest[i]; + set_pirq_eoi(d, irq); + /* + * Could check here whether the guest unmasked the event by now + * (or perhaps just re-issue the send_guest_pirq()), and if it + * can now accept the event, + * - clear all the pirq_eoi bits we already set, + * - re-enable the vector, and + * - skip the timer setup below. + */ + } init_timer(&irq_guest_eoi_timer[irq], irq_guest_eoi_timer_fn, desc, smp_processor_id()); set_timer(&irq_guest_eoi_timer[irq], NOW() + MILLISECS(1)); @@ -379,16 +418,25 @@ int pirq_acktype(int irq) int pirq_guest_eoi(struct domain *d, int irq) { irq_desc_t *desc; + irq_guest_action_t *action; if ( (irq < 0) || (irq >= NR_IRQS) ) return -EINVAL; desc = &irq_desc[irq]; spin_lock_irq(&desc->lock); - if ( test_and_clear_bit(irq, &d->pirq_mask) && - (--((irq_guest_action_t *)desc->action)->in_flight == 0) ) + action = (irq_guest_action_t *)desc->action; + + if ( action->ack_type == ACKTYPE_NONE ) + { + ASSERT(!test_bit(irq, d->pirq_mask)); + stop_timer(&irq_guest_eoi_timer[irq]); + _irq_guest_eoi(desc); + } + + if ( test_and_clear_bit(irq, &d->pirq_mask) && (--action->in_flight == 0) ) { - ASSERT(((irq_guest_action_t*)desc->action)->ack_type == ACKTYPE_UNMASK); + ASSERT(action->ack_type == ACKTYPE_UNMASK); desc->handler->end(irq); } spin_unlock_irq(&desc->lock); @@ -488,6 +536,11 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share) action->guest[action->nr_guests++] = v->domain; + if ( action->ack_type != ACKTYPE_NONE ) + set_pirq_eoi(v->domain, irq); + else + clear_pirq_eoi(v->domain, irq); + out: spin_unlock_irqrestore(&desc->lock, flags); return rc; diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h index 72857b9ab2..41391b3350 100644 --- a/xen/include/asm-ia64/domain.h +++ b/xen/include/asm-ia64/domain.h @@ -177,6 +177,10 @@ struct arch_domain { /* Address of SAL emulator data */ struct xen_sal_data *sal_data; + /* Shared page for notifying that explicit PIRQ EOI is required. */ + unsigned long *pirq_eoi_map; + unsigned long pirq_eoi_map_mfn; + /* Address of efi_runtime_services_t (placed in domain memory) */ void *efi_runtime; /* Address of fpswa_interface_t (placed in domain memory) */